package com.swak.loadbalance.impl;

import java.util.List;
import java.util.concurrent.ThreadLocalRandom;

import com.swak.loadbalance.Referer;

/**
 * 加权随机
 * 
 * @author lifeng
 * @date 2020年4月30日 上午10:25:27
 */
public class WeightingRandomLoadBalance<T> extends AbstractLoadBalance<T> {

	@Override
	protected Referer<T> doSelect() {
		List<Referer<T>> referers = this.getReferers();
		// Number of invokers
		int length = referers.size();
		// Every invoker has the same weight?
		boolean sameWeight = true;
		// the weight of every invokers
		int[] weights = new int[length];

		// the first invoker's weight
		int firstWeight = referers.get(0).getWeight();
		weights[0] = firstWeight;
		// The sum of weights
		int totalWeight = firstWeight;
		for (int i = 1; i < length; i++) {
			int weight = referers.get(i).getWeight();
			// save for later use
			weights[i] = weight;
			// Sum
			totalWeight += weight;
			if (sameWeight && weight != firstWeight) {
				sameWeight = false;
			}
		}
		if (totalWeight > 0 && !sameWeight) {
			// If (not every invoker has the same weight & at least one invoker's weight>0),
			// select randomly based on totalWeight.
			int offset = ThreadLocalRandom.current().nextInt(totalWeight);
			// Return a invoker based on the random value.
			for (int i = 0; i < length; i++) {
				offset -= weights[i];
				if (offset < 0) {
					return referers.get(i);
				}
			}
		}

		int index = (int) (ThreadLocalRandom.current().nextDouble() * referers.size());
		return referers.get(index % referers.size());
	}
}
